<!doctype html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vue条件渲染详解与示例</title>
    <script src="https://unpkg.com/vue@3.4.0"></script>
    <style>
      body {
        font-family: 'Consolas', '微软雅黑';
        max-width: 1200px;
        margin: 0 auto;
        padding: 20px;
        background-color: #f5f5f5;
        line-height: 1.6;
      }
      code {
        font-family: 'Consolas', '微软雅黑';
      }
      .container {
        background: white;
        padding: 20px;
        border-radius: 10px;
        box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
        margin-bottom: 20px;
      }
      h1 {
        color: #2c3e50;
        text-align: center;
        margin-bottom: 30px;
        font-size: 2.5em;
      }
      h2 {
        color: #34495e;
        border-bottom: 3px solid #3498db;
        padding-bottom: 10px;
        margin-top: 30px;
      }
      h3 {
        color: #2980b9;
        margin-top: 25px;
      }
      .demo-section {
        margin: 20px 0;
        padding: 20px;
        border: 1px solid #ddd;
        border-radius: 8px;
        background-color: #f9f9f9;
      }
      .code-block {
        background-color: #2d3748;
        border-radius: 8px;
        padding: 0;
        margin: 15px 0;
        overflow: hidden;
      }
      .code-block textarea {
        height: auto;
        min-height: 200px;
        font-family: 'Consolas', '微软雅黑';
        font-size: 13px;
        padding: 15px;
        border: none;
        border-radius: 0;
        background-color: transparent;
        resize: none;
        line-height: 1.5;
        box-sizing: border-box;
        color: #e2e8f0;
        width: 100%;
        outline: none;
      }
      .user-info {
        background: #d4edda;
        padding: 15px;
        border-radius: 5px;
        border-left: 4px solid #28a745;
        color: #155724;
      }
      .warning {
        background: #fff3cd;
        padding: 15px;
        border-radius: 5px;
        border-left: 4px solid #ffc107;
        color: #856404;
      }
      .error {
        background: #f8d7da;
        padding: 15px;
        border-radius: 5px;
        border-left: 4px solid #dc3545;
        color: #721c24;
      }
      .info {
        background: #d1ecf1;
        padding: 15px;
        border-radius: 5px;
        border-left: 4px solid #17a2b8;
        color: #0c5460;
      }
      button {
        background-color: #3498db;
        color: white;
        padding: 10px 20px;
        border: none;
        border-radius: 5px;
        cursor: pointer;
        font-size: 16px;
        margin: 5px;
        transition: background-color 0.3s;
      }
      button:hover {
        background-color: #2980b9;
      }
      input[type='number'] {
        padding: 8px 12px;
        border: 1px solid #ddd;
        border-radius: 4px;
        font-size: 14px;
        margin: 5px;
      }
      .comparison-container {
        display: flex;
        gap: 20px;
        margin-top: 15px;
      }
      .comparison-item {
        flex: 1;
        padding: 15px;
        border: 1px solid #ddd;
        border-radius: 5px;
      }
      .v-if-demo {
        background: #e3f2fd;
        border-left: 4px solid #2196f3;
      }
      .v-show-demo {
        background: #e8f5e8;
        border-left: 4px solid #4caf50;
      }
      .output {
        background-color: #ecf0f1;
        padding: 15px;
        border-radius: 5px;
        margin-top: 10px;
        border-left: 4px solid #3498db;
      }
      .highlight {
        background-color: #fff3cd;
        padding: 2px 4px;
        border-radius: 3px;
      }
      .performance-note {
        background: #fff3cd;
        padding: 15px;
        border-radius: 5px;
        border-left: 4px solid #ffc107;
        margin: 15px 0;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <h1>Vue条件渲染详解与示例</h1>

      <!-- 概述 -->
      <div class="container">
        <h2>概述</h2>
        <p>Vue.js提供了多种条件渲染指令，用于根据数据的状态动态显示或隐藏DOM元素。主要包括：</p>
        <ul>
          <li>
            <span class="highlight">v-if</span>
            ：条件性地渲染元素，元素会被真正创建或销毁
          </li>
          <li>
            <span class="highlight">v-else-if</span>
            ：配合v-if使用，提供多重条件判断
          </li>
          <li>
            <span class="highlight">v-else</span>
            ：配合v-if使用，提供默认分支
          </li>
          <li>
            <span class="highlight">v-show</span>
            ：通过CSS的display属性控制元素显示/隐藏
          </li>
          <li>
            <span class="highlight">template</span>
            ：用于包装多个元素进行条件渲染
          </li>
        </ul>
      </div>

      <!-- 1. v-if基础用法 -->
      <div class="container">
        <h2>1. v-if 基础用法</h2>
        <p>
          <code>v-if</code>
          指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回真值时被渲染。
        </p>

        <div class="code-block">
          <textarea readonly>
<div>
  <button @click="showMessage = !showMessage">
    {{ showMessage ? '隐藏' : '显示' }}消息
  </button>
  <p v-if="showMessage">这是一条消息！</p>
</div>
            </textarea>
        </div>

        <div class="demo-section">
          <h3>实际演示</h3>
          <button @click="showMessage = !showMessage">
            {{ showMessage ? '隐藏' : '显示' }}消息
          </button>
          <p v-if="showMessage" class="info">这是一条消息！</p>
          <div class="output">
            <strong>当前状态：</strong>
            showMessage = {{ showMessage }}
          </div>
        </div>
      </div>

      <!-- 2. 多重条件渲染 -->
      <div class="container">
        <h2>2. 多重条件渲染 (v-if / v-else-if / v-else)</h2>
        <p>
          可以使用
          <code>v-else-if</code>
          和
          <code>v-else</code>
          来构建更复杂的条件逻辑。
        </p>

        <div class="code-block">
          <textarea readonly>
<div>
  <input type="number" v-model.number="score" placeholder="输入分数(0-100)" />
  <div v-if="score >= 90" class="excellent">
    优秀！分数：{{ score }}
  </div>
  <div v-else-if="score >= 80" class="good">
    良好！分数：{{ score }}
  </div>
  <div v-else-if="score >= 60" class="pass">
    及格！分数：{{ score }}
  </div>
  <div v-else-if="score >= 0" class="fail">
    不及格！分数：{{ score }}
  </div>
  <div v-else class="invalid">
    请输入有效分数
  </div>
</div>
                </textarea
          >
        </div>

        <div class="demo-section">
          <h3>实际演示</h3>
          <input type="number" v-model.number="score" placeholder="输入分数(0-100)" />
          <div v-if="score >= 90" class="user-info">优秀！分数：{{ score }}</div>
          <div v-else-if="score >= 80" class="warning">良好！分数：{{ score }}</div>
          <div v-else-if="score >= 60" class="info">及格！分数：{{ score }}</div>
          <div v-else-if="score >= 0" class="error">不及格！分数：{{ score }}</div>
          <div v-else class="warning">请输入有效分数</div>
          <div class="output">
            <strong>当前分数：</strong>
            {{ score }} (类型：{{ typeof score }})
          </div>
        </div>
      </div>

      <!-- 3. v-show与v-if对比 -->
      <div class="container">
        <h2>3. v-show 与 v-if 对比</h2>
        <p>
          理解
          <code>v-if</code>
          和
          <code>v-show</code>
          的区别对于性能优化很重要：
        </p>
        <ul>
          <li>
            <strong>v-if</strong>
            ："真正"的条件渲染，会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建
          </li>
          <li>
            <strong>v-show</strong>
            ：简单地切换元素的CSS属性
            <code>display</code>
            ，元素始终会被渲染并保留在DOM中
          </li>
        </ul>

        <div class="code-block">
          <textarea readonly>
<div>
  <button @click="toggleDisplay">切换显示</button>
  <p>切换次数：{{ toggleCount }}</p>
  
  <div class="comparison-container">
    <div class="v-if-demo">
      <h4>v-if (创建/销毁元素)</h4>
      <div v-if="isVisible">
        v-if内容 - 每次切换都会重新创建
        <br>创建时间：{{ new Date().toLocaleTimeString() }}
      </div>
    </div>
    
    <div class="v-show-demo">
      <h4>v-show (切换CSS display)</h4>
      <div v-show="isVisible">
        v-show内容 - 始终存在DOM中
        <br>创建时间：{{ createdTime }}
      </div>
    </div>
  </div>
</div>
                </textarea
          >
        </div>

        <div class="demo-section">
          <h3>实际演示</h3>
          <button @click="toggleDisplay">切换显示</button>
          <p>
            <strong>切换次数：</strong>
            {{ toggleCount }}
          </p>

          <div class="comparison-container">
            <div class="comparison-item v-if-demo">
              <h4>v-if (创建/销毁元素)</h4>
              <div v-if="isVisible">
                v-if内容 - 每次切换都会重新创建
                <br />
                <small>创建时间：{{ new Date().toLocaleTimeString() }}</small>
              </div>
              <div v-else class="info">元素已被销毁</div>
            </div>

            <div class="comparison-item v-show-demo">
              <h4>v-show (切换CSS display)</h4>
              <div v-show="isVisible">
                v-show内容 - 始终存在DOM中
                <br />
                <small>创建时间：{{ createdTime }}</small>
              </div>
            </div>
          </div>

          <div class="output">
            <strong>当前状态：</strong>
            isVisible = {{ isVisible }}
          </div>
        </div>

        <div class="performance-note">
          <h4>性能考虑</h4>
          <ul>
            <li>
              <strong>v-if</strong>
              有更高的切换开销，适合条件很少改变的场景
            </li>
            <li>
              <strong>v-show</strong>
              有更高的初始渲染开销，适合需要非常频繁切换的场景
            </li>
          </ul>
        </div>
      </div>

      <!-- 4. template元素分组 -->
      <div class="container">
        <h2>4. template 元素分组</h2>
        <p>
          当需要切换多个元素时，可以使用
          <code>&lt;template&gt;</code>
          元素作为不可见的包裹元素。
        </p>

        <div class="code-block">
          <textarea readonly>
<div>
  <button @click="showUserInfo = !showUserInfo">
    {{ showUserInfo ? '隐藏' : '显示' }}用户信息
  </button>
  
  <template v-if="showUserInfo">
    <h4>用户信息</h4>
    <p><strong>姓名：</strong>张三</p>
    <p><strong>邮箱：</strong>zhangsan@example.com</p>
    <p><strong>电话：</strong>138****8888</p>
    <p><strong>地址：</strong>北京市朝阳区</p>
  </template>
  
  <template v-else>
    <p class="info">点击按钮查看用户信息</p>
  </template>
</div>
                </textarea
          >
        </div>

        <div class="demo-section">
          <h3>实际演示</h3>
          <button @click="showUserInfo = !showUserInfo">
            {{ showUserInfo ? '隐藏' : '显示' }}用户信息
          </button>

          <template v-if="showUserInfo">
            <div class="user-info">
              <h4>用户信息</h4>
              <p>
                <strong>姓名：</strong>
                张三
              </p>
              <p>
                <strong>邮箱：</strong>
                zhangsan@example.com
              </p>
              <p>
                <strong>电话：</strong>
                138****8888
              </p>
              <p>
                <strong>地址：</strong>
                北京市朝阳区
              </p>
            </div>
          </template>

          <template v-else>
            <div class="info">
              <p>点击按钮查看用户信息</p>
            </div>
          </template>

          <div class="output">
            <strong>显示状态：</strong>
            showUserInfo = {{ showUserInfo }}
          </div>
        </div>
      </div>

      <!-- 5. 高级用法和最佳实践 -->
       <div class="container">
        <h2>5. 高级用法和最佳实践</h2>

        <h3>5.1 条件渲染与列表渲染结合</h3>
        <div class="code-block">
          <textarea readonly>
<div>
  <button @click="showActiveOnly = !showActiveOnly">
    {{ showActiveOnly ? '只显示活跃用户' : '显示全部' }}
  </button>
  <ul>
    <template v-for="user in users" :key="user?.id">
      <li v-if="user && (!showActiveOnly || user.active)" class="user-item">
          user.name  -  user.active ? '活跃' : '非活跃 这一句解析不了！'
      </li>
    </template>
  </ul>
</div>
                </textarea
          >
        </div>
        <div class="demo-section">
          <h3>实际演示</h3>
          <button @click="showActiveOnly = !showActiveOnly">
            {{ showActiveOnly ? '只显示活跃用户' : '显示全部' }}
          </button>

          <ul style="list-style-type: none; padding: 0">
            <template v-for="user in users" :key="user?.id || Math.random()">
              <li
                v-if="user && (!showActiveOnly || user.active)"
                :class="user.active ? 'user-info' : 'warning'"
                style="margin: 5px 0; padding: 10px; border-radius: 5px"
              >
                {{ user.name }} - {{ user.active ? '活跃' : '非活跃' }}
              </li>
            </template>
          </ul>

          <div class="output">
            <strong>过滤状态：</strong>
            {{ showActiveOnly ? '只显示活跃用户' : '显示全部用户' }}
            <br />
            <strong>显示用户数：</strong>
            {{ showActiveOnly ? users.filter(u => u && u.active).length : users.length }}
          </div>
        </div>
      </div>

      <!-- 总结 -->
      <div class="container">
        <h2>总结</h2>
        <div class="info">
          <h3>关键要点：</h3>
          <ol>
            <li>
              <strong>选择合适的指令：</strong>
              根据使用场景选择 v-if 或 v-show
            </li>
            <li>
              <strong>性能考虑：</strong>
              频繁切换使用 v-show，条件很少改变使用 v-if
            </li>
            <li>
              <strong>代码可读性：</strong>
              合理使用 v-else-if 和 v-else 提高代码可读性
            </li>
            <li>
              <strong>元素分组：</strong>
              使用 template 元素对多个元素进行条件渲染
            </li>
            <li>
              <strong>避免同时使用：</strong>
              不要在同一元素上同时使用 v-if 和 v-for
            </li>
          </ol>
        </div>
      </div>
    </div>

    <script>
      const { createApp, ref } = Vue

      const App = {
        setup() {
          const showMessage = ref(false)
          const score = ref(85)
          const isVisible = ref(true)
          const toggleCount = ref(0)
          const showUserInfo = ref(false)
          const createdTime = ref(new Date().toLocaleTimeString())
          const showActiveOnly = ref(false)
          const users = ref([
            { id: 1, name: '张三', active: true },
            { id: 2, name: '李四', active: false },
            { id: 3, name: '王五', active: true },
            { id: 4, name: '赵六', active: false }
          ])

          const toggleDisplay = () => {
            isVisible.value = !isVisible.value
            toggleCount.value++
          }

          return {
            showMessage,
            score,
            isVisible,
            toggleCount,
            showUserInfo,
            createdTime,
            showActiveOnly,
            users,
            toggleDisplay
          }
        }
      }

      createApp(App).mount('#app')
    </script>
  </body>
</html>
